import PanelBase from "./PanelBase";
import LayerMgr from "./LayerMgr";
import mi from "../MI";
import AppConst from "../AppConst";
import MiUtil from "../util/MiUtil";


export default class PanelMgr {
    private static _panels: { [panelName: string]: PanelBase; } = {};
    private static _maskPrefab: cc.Prefab = null;
    private static _showPanelMask: cc.Node = null;


    public static init(): void {
        cc.loader.loadRes('mi/core/Mask', (err: Error, maskPrefab: cc.Prefab) => {
            if (!err) {
                this._maskPrefab = maskPrefab;
            } else {
                cc.error('找不到遮罩资源 mi/core/Mask err:', err);
            }
        });
    }


    public static show(panelCls: any, ...panelArgs: any[]) {
        if (this._panels[panelCls]) {
            const current = this._panels[panelCls] as PanelBase;
            current.reset(panelArgs);
            current.skin.active = false;
            current.showing();
            LayerMgr.setLayer(current.skin, AppConst.viewLayer.Panel);

            this.startShowPanel(current, current.panelShowStyle, true);
        } else {
            const panelName = panelCls.name;
            const current = new panelCls() as PanelBase;

            this._panels[panelName] = current;
            current.panelName = panelName;
            current.init(panelArgs);

            cc.loader.loadRes(current.skinPath, (err: Error, panelPrefab: cc.Prefab) => {
                if (!err) {
                    const skin = cc.instantiate(panelPrefab);

                    current.skin = skin;
                    current.initDone();
                    current.skin.active = false;
                    current.showing();
                    LayerMgr.setLayer(current.skin, AppConst.viewLayer.Panel);
                    this.maskStyle(current);

                    this.startShowPanel(current, current.panelShowStyle, true);
                } else {
                    cc.error('找不到[', panelCls, ']面板皮肤:', current.skinPath + ', err:', err);
                }
            });
        }
    }

    public static isAlive(panelCls: any): boolean {
        return this._panels[panelCls] != undefined && this._panels[panelCls].skin.active;
    }

    public static updateView(panelCls: any, ...args: any[]): void {
        if (!this.isAlive(panelCls)) {
            cc.error('[%s]更新 view 失败, 未打开或未激活', panelCls.name);
            return;
        }
        this._panels[panelCls].updateView(args);
    }

    public static hidePanel(panelName: string) {
        if (!this._panels[panelName]) {
            cc.error("关闭的面板[%s]不存在", panelName);
            return;
        }

        const pb = this._panels[panelName];
        this.startShowPanel(pb, pb.panelShowStyle, false);
    }

    public static destroyPanel(panelName: string, force?: boolean) {
        if (!this._panels[panelName]) {
            cc.error("销毁的面板[%s]不存在", panelName);
            return;
        }

        let pb = this._panels[panelName];
        pb.hiding();
        pb.skin.active = false;
        pb.hided();

        if (force || !pb.cache) {
            delete this._panels[panelName];
            pb.destroy();
            pb = null;
        }
    }


    private static startShowPanel(go: PanelBase, showStyle: number, isOpen: boolean) {
        this.showPanelBefore();

        switch (showStyle) {
            case AppConst.panelShowStyle.Normal:
                this.showNormal(go, isOpen);
                break;
            case AppConst.panelShowStyle.CenterSmallToBig:
                this.centerScaleBigNormal(go, isOpen);
                break;
            case AppConst.panelShowStyle.LeftToCenter:
                this.leftAndRightToSlide(go, false, isOpen);
                break;
            case AppConst.panelShowStyle.RightToCenter:
                this.leftAndRightToSlide(go, true, isOpen);
                break;
            case AppConst.panelShowStyle.UpToCenter:
                this.upAndDownToSlide(go, true, isOpen);
                break;
            case AppConst.panelShowStyle.DownToCenter:
                this.upAndDownToSlide(go, false, isOpen);
                break;
        }
    }

    // #region 显示方式
    /** 默认显示 */
    private static showNormal(go: PanelBase, isOpen: boolean) {
        if (isOpen) {
            go.skin.active = true;
            go.showed();
        } else {
            this.destroyPanel(go.panelName);
        }
        this.showPanelAfter();
    }

    /** 中间变大 */
    private static centerScaleBigNormal(go: PanelBase, isOpen: boolean) {
        if (isOpen) {
            go.skin.scale = 0;
            go.skin.active = true;
            cc.tween(go.skin).to(go.openDuration, { scale: 1 }, { easing: 'smooth' }).call(() => {
                go.showed();
                this.showPanelAfter();
            }).start();
        } else {
            cc.tween(go.skin).to(go.openDuration, { scale: 0 }, { easing: 'smooth' }).call(() => {
                this.destroyPanel(go.panelName);
                this.showPanelAfter();
            }).start();
        }
    }

    /** 左右往中 */
    private static leftAndRightToSlide(go: PanelBase, isRight: boolean, isOpen: boolean) {
        var from: cc.Vec2 = isRight ? cc.v2(cc.winSize.width / 2, 0) : cc.v2(-cc.winSize.width / 2, 0);
        var to: cc.Vec2 = cc.Vec2.ZERO;
        if (isOpen) {
            go.skin.setPosition(from);
            go.skin.active = true;
            cc.tween(go.skin).to(go.openDuration, { position: to }, { easing: 'smooth' })
                .call(() => {
                    go.showed();
                    this.showPanelAfter();
                })
                .start();
        } else {
            cc.tween(go.skin).to(go.openDuration, { position: from }, { easing: 'smooth' })
                .call(() => {
                    this.destroyPanel(go.panelName);
                    this.showPanelAfter();
                })
                .start();
        }
    }

    /** 上下往中 */
    private static upAndDownToSlide(go: PanelBase, isUp: boolean, isOpen: boolean) {
        var from: cc.Vec2 = isUp ? cc.v2(0, cc.winSize.height / 2) : cc.v2(0, -cc.winSize.height / 2);
        var to: cc.Vec2 = cc.Vec2.ZERO;
        if (isOpen) {
            go.skin.setPosition(from);
            go.skin.active = true;
            cc.tween(go.skin).to(go.openDuration, { position: to }, { easing: 'smooth' })
                .call(() => {
                    go.showed();
                    this.showPanelAfter();
                })
                .start();
        } else {
            cc.tween(go.skin).to(go.openDuration, { position: from }, { easing: 'smooth' })
                .call(() => {
                    this.destroyPanel(go.panelName);
                    this.showPanelAfter();
                })
                .start();
        }
    }
    // #endregion

    // #region 遮罩方式
    private static maskStyle(go: PanelBase): void {
        let mask = cc.instantiate(this._maskPrefab);
        mask.zIndex = -2;
        go.skin.addChild(mask);
        MiUtil.setWidget(mask, go.skin.parent);

        if ((go.panelMaskStyle & AppConst.panelMaskStyle.NoThrough) > 0) {
            mask.addComponent(cc.BlockInputEvents)
        }
        if ((go.panelMaskStyle & AppConst.panelMaskStyle.Black) > 0) {
            mask.opacity = 125;
        }
        if ((go.panelMaskStyle & AppConst.panelMaskStyle.Close) > 0) {
            // 添加一个跟面板一样大小的防穿透放组件在关闭组件上面
            const mask2 = cc.instantiate(this._maskPrefab);
            mask2.zIndex = -1;
            go.skin.addChild(mask2);
            MiUtil.setWidget(mask2);
            mask2.addComponent(cc.BlockInputEvents);

            if (!mask.getComponent(cc.BlockInputEvents)) mask.addComponent(cc.BlockInputEvents);
            mask.on(cc.Node.EventType.TOUCH_START, (_event: cc.Button) => {
                this.hidePanel(go.panelName);
            });
        }
    }


    /** 显示面板时如果有进场动画, 这时场景有可能是没有遮罩的, 这样就会点击到其它 ui */
    private static showPanelBefore(): void {
        if (!this._showPanelMask) {
            this._showPanelMask = cc.instantiate(this._maskPrefab);
            MiUtil.setWidget(this._showPanelMask);
            this._showPanelMask.addComponent(cc.BlockInputEvents);
        }
        this._showPanelMask.active = true;
        LayerMgr.setLayer(this._showPanelMask, AppConst.viewLayer.Top);
    }

    private static showPanelAfter(): void {
        this._showPanelMask.active = false;
    }
    // #endregion
}
